/* gps.h -- interface of the libgps library
 *
 * This file is Copyright 2010 by the GPSD project
 * SPDX-License-Identifier: BSD-2-clause
 */
#ifndef _GPSD_GPS_H_
#define _GPSD_GPS_H_

#ifdef __cplusplus
extern "C" {
#endif

#include <inttypes.h>   // stdint.h would be smaller but not all have it
#include <limits.h>
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <time.h>

/*
 * 4.1 - Base version for initial JSON protocol (Dec 2009, release 2.90)
 * 4.2 - AIS application IDs split into DAC and FID (July 2010, release 2.95)
 * 5.0 - MAXCHANNELS bumped from 20 to 32 for GLONASS (Mar 2011, release 2.96)
 *       gps_open() becomes reentrant, what gps_open_r() used to be.
 *       gps_poll() removed in favor of gps_read().  The raw hook is gone.
 *       (Aug 2011, release 3.0)
 * 5.1 - GPS_PATH_MAX uses system PATH_MAX; split24 flag added. New
 *       model and serial members in part B of AIS type 24, conforming
 *       with ITU-R 1371-4. New timedrift structure (Nov 2013, release 3.10).
 * 6.0 - AIS type 6 and 8 get 'structured' flag; GPS_PATH_MAX
 *       shortened because devices has moved out of the tail union. Sentence
 *       tag fields dropped from emitted JSON. The shape of the skyview
 *       structure has changed to make working with the satellites-used
 *       bits less confusing. (January 2015, release 3.12).
 * 6.1 - Add navdata_t for more (nmea2000) info.
 * 7.0 - add gps_fix_t.ecef (February 2018)
 *       changed prototype of gps_read() to add buffer parameters
 *       increased length of devconfig_t.subtype
 *       add gnssid:svid:sigid to satellite_t
 *       add mtime to attitude_t
 *       changed MAXCHANNELS
 * 8.0 - Change shape of rawdata_t.
 *       Added values for gps_data_t->status
 *       Remove epe from gps_data_t, it duplicates gps_fix_t eph
 *       Added sep (estimated spherical error, 3D)
 *       Note: Some GPS call eph as epe, others call sep as epe
 *       Add gps_fix_t datum string, and qErr
 *       enlarge subtype to hold ZED-F9 string
 *       MAXCHANNELS bumped from 120 to 140
 *       Try to make PRN be NMEA 2.x-4.0 compliant, not 4.10 or u-blox
 * 9.0   add NED and geoid_sep variables to gps_fix_t
 *       add health variable to satellite_t
 *       change satellite_t elevation and azimuth to double
 *       satellite_t elevation, azimuth, and ss use NAN for unknown value.
 *       add altMSL, and depth, to gps_fix_t
 *       add altHAE to gps_fix_t
 *       mark altitude in gps_fix_t as deprecated and undefined
 *       Move mag_var from gps_device_t to magnetic_var gps_data_t.
 *       add dgps_age and dgps_station, to gps_fix_t
 *       Change gps_fix_t.time from timestamp_t to timespec_t
 *       Change gps_data_t.skyview_time from timestamp_t to timespec_t
 *       Change gps_data_t.online from timestamp_t to timespec_t
 *       Change gpst_t.utctime from double to timespec_t
 *       Change devices.time from timestamp_t to timespec_t
 *       Change sub4_18.d_tot from timestamp_t to time_t t_tot
 *       Change devconfig_t.activated, cycle & mincycle to timespec_t
 *       Remove unused timestamp() and unix_to_iso8601().
 *       Remove unused iso8601_to_unix().
 *       Remove unused struct timestamp_t entirely
 *       Add DEG_NORM()
 *       Move toff and pps out of gps_data_t.union.
 *       Move gps_fix_t.qErr to gps_data_t.
 *       Split devconfig_t.subtype into subtype and subtype1
 * 9.1   Add leap_seconds to gps_data_t
 *       Fix rtcm3_1029_t.text length
 *       Add/change many rtcm2 structs
 *       Add/change many rtcm3 structs
 * 10    Move gps_data_t->status to gps_fix_t.status for better fix merging
 *       Add wspeedt, wspeedr, wanglem, wanglet, wangler to  gps_fix_t
 *       Remove unused gps_data_t.navadata_t.
 *       Add relPosL and relPosH to gps_fix_t.NED
 * 11    long l_toa becomes unsigned long l_toa
 *       fix sub4_18 types.
 * 12    subframe_t expanded for more gnssId's, WN, etc.
 *       Add orbit_t for generic orbital parameters
 *       Add subframe.orbit and subframe.orbit1 to store orbit_t's
 *       Add gyro_temp, gyro_z, msg, timeTag, to attitude_t
 *       add imu[], and matching IMU_SET flag
 *       move attitude out of the union, to stop conflicts.
 * 13    Add rtcm3_msm
 *       fix tow in never used struct rtcm3_1015_t
 *       remove never used struct rtcm3_1016_t and struct rtcm3_1017_t
 *       add struct baseline_t
 * 14    Move threee visibilize() into one gps_visibilize() here.
 *       Move gpsd_hexpack() to here as gps_hexpack()
 *       Move gpsd_hexdump() to here as gps_hexdump()
 *       Add prRes and qualityInd to satellite_t
 *       Add fixsource_t and watch_t to gps_data_t
 *       move privdata_t here from libgps/gps_sock.c
 *       Add rot (Rate Of Turn), mheading, to struct attitude_t
 *       Add wtemp to gps_fix_t
 */
#define GPSD_API_MAJOR_VERSION  14      // bump on incompatible changes
#define GPSD_API_MINOR_VERSION  0       // bump on compatible changes

#define MAXCHANNELS     140     // u-blox 9 tracks 140 signals
#define MAXUSERDEVS     4       // max devices per user
#define GPS_PATH_MAX    128     // for names like /dev/serial/by-id/...

#define GPS_JSON_COMMAND_MAX    80
// u-blox 9 can make really long JSON in "RAW" messages
#define GPS_JSON_RESPONSE_MAX   10240

// normalize degrees to 0 to 359
#define DEG_NORM(deg) \
    if (0 > (deg)) {(deg) += 360;} else if (360 <= (deg)) {(deg) -= 360;};

/*
 * The structure describing an uncertainty volume in kinematic space.
 * This is what GPSes are meant to produce; all the other info is
 * technical impedimenta.
 *
 * All the information in this structure was considered "valid"
 * by the GPS at the time of update.  But "valid" doubles are likely
 * the same as NaN. Check "gps_mask_t set" before using integers and flags.
 *
 * Error estimates are at 95% confidence.  Except when they are not.
 *
 * WARNING!  loss of precision telling time as a double.
 * UNIX time to nanoSec precision is 62 significant bits
 * UNIX time to nanoSec precision after 2038 is 63 bits
 * That is why gpsd uses struct timespec.
 *
 * For more info:  https://gpsd.io/gpsd-numbers-matter.html
 *
 * The u-blox ZED-F9P reports 0.1 mm, and 1e-9 (0.000000001) degree,
 * precision.  That is about 12 decimal digits of precision.
 * It is certainly not that accurate, maybe soon.
 *
 * this easily fits in a C double which has 15.95 digits of precision
 * printf() format %f defaults to %.6f, which will truncate the result.
 * so print with %.7f, or even %9f, if you have a survey grade GPS.
 *
 * For more info:  https://gpsd.io/gpsd-numbers-matter.html
 *
 * All double values use NAN to indicate data not available.
 * WARNING: Check all floats and doubles with isfinite() before using them!
 * isnan() is not sufficient.
 *
 * For more info:  https://gps.io/gpsd-numbers-matter.html
 */
struct timespec{
	time_t tv_sec;
	long tv_nsec;
};
typedef struct timespec timespec_t;     // Unix time as sec, nsec

/* Baseline data is here.  Some receivers, like the Skytraq
 * PX1172RH_DS, report two baselines.  One from a fixed
 * (surveyed in) base to the mving base, and one from the moving
 * base to the moving rover.
 */
struct baseline_t {
    /* status, aka mode, valid values:
     * STATUS_UNK, STATUS_RTK_FIX, STATUS_RTK_FLT
     */
    int status;
    double east;        // East projection of baseline, meters
    double north;       // North projection of baseline, meters
    double up;          // Up projection of baseline, meters
    double length;      // length, meters.
    double course;      // course, degrees
    double ratio;       // RTK AR Ratio
};

/* GPS error estimates are all over the map, and often unspecified.
 * try for 1-sigma if we can... */
struct gps_fix_t {
    timespec_t time;            // Time of update
    int    mode;                // Mode of fix
#define MODE_NOT_SEEN   0       // mode update not seen yet
#define MODE_NO_FIX     1       // none
#define MODE_2D         2       // good for latitude/longitude
#define MODE_3D         3       // good for altitude/climb too

    /* GPS status, aka fix type, is a modifier (adjective) to
     * gps_data.mode.  It is not a replacement for, or superset of, mode.
     * It is almost, but not quite, the same as the NMEA 4.x xxGGA GPS
     * Quality Indicator Values.  Many GNSS receivers do not supply it.
     */
    int    status;              // What kind of fix?
#define STATUS_UNK      0       // Unknown status
// plain GPS (SPS Mode), without DGPS, PPS, RTK, DR, etc.
#define STATUS_GPS      1
#define STATUS_DGPS     2       // with DGPS
#define STATUS_RTK_FIX  3       // with RTK Fixed
#define STATUS_RTK_FLT  4       // with RTK Float
#define STATUS_DR       5       // with dead reckoning
#define STATUS_GNSSDR   6       // with GNSS + dead reckoning
#define STATUS_TIME     7       // time only (surveyed in, manual)
// Note that STATUS_SIM and MODE_NO_FIX can go together.
#define STATUS_SIM      8       // simulated
/* yes, Precise Positioning Service (PPS)
 * Not to be confused with Pulse per Second (PPS)
 * PPS is the encrypted military P(Y)-code */
#define STATUS_PPS_FIX  9

    double ept;         // Expected time uncertainty, seconds
    double latitude;    // Latitude in degrees (valid if mode >= 2)
    double epy;         // Latitude position uncertainty, meters
    double longitude;   // Longitude in degrees (valid if mode >= 2)
    double epx;         // Longitude position uncertainty, meters
    double altitude;    // DEPRECATED, undefined.
    double altHAE;      /* Altitude, height above ellipsoid.
                         * in meters and probably WGS84
                         * (valid if mode == 3)
                         * MSL = altHAE - geoid_sep */
    double altMSL;      // Altitude MSL (maybe EGM2008)
    double epv;         // Vertical position uncertainty, meters
    double track;       // Course made good (relative to true north)
    double epd;         // Track uncertainty, degrees
    double speed;       // Speed over ground, meters/sec
    double eps;         // Speed uncertainty, meters/sec
    double climb;       // Vertical speed, meters/sec
    double epc;         // Vertical speed uncertainty
    // estimated position error horizontal (2D). Meters, maybe 50%, maybe 95%
    // aka estimated position error (epe)
    double eph;         // estimated position error horizontal (2D)
    // spherical error probability, 3D. Meters, maybe 50%, maybe 95%
    // Garmin, not gpsd, calls this estimated position error (epe)
    double sep;
    /* Geoid separation (ellipsoid separation)
     * Height of MSL ellipsoid (geoid) above WGS84 ellipsoid.
     * Positive is MSL above WGS84. In meters */
    double geoid_sep;

    double magnetic_track;  // Course (relative to Magnetic North)
    double magnetic_var;    // magnetic variation in degrees
    // depth in meters, probably depth of water under the keel
    double depth;
    double wtemp;           // water temp, degrees C

    // ECEF data, all data in meters, and meters/second, or NaN
    struct {
        double x, y, z;         // ECEF x, y, z
        double pAcc;            // 3D Position Accuracy Estimate, likely SEP
        double vx, vy, vz;      // ECEF x, y, z velocity
        double vAcc;            // Velocity Accuracy Estimate, probably SEP
    } ecef;
    // NED data, all data in meters, and meters/second, or NaN
    struct {
        double relPosN, relPosE, relPosD;   // NED relative positions
        double relPosL, relPosH;            // relative length and heading
        double velN, velE, velD;            // NED velocities
    } NED;
    char datum[40];             // map datum
    // DGPS stuff, often from xxGGA, or xxGNS
    double dgps_age;       // age of DGPS data in seconds, -1 invalid
    /* DGPS Station used, max size is a guess
     * NMEA 2 says 0000-1023
     * RTCM 3, station ID is 0 to 4095.
     * u-blox UBX-NAV-DGPS is 16 bit integer */
    int dgps_station;           // DGPS station ID, -1 invalid
    double wanglem;             // Wind angle, magnetic, m/s
    double wangler;             // Wind angle, relative, m/s
    double wanglet;             // Wind angle, true, m/s
    double wspeedr;             // Wind speed, relative, m/s
    double wspeedt;             // Wind speed, true, m/s
    struct baseline_t base;     // baseline from fixed base
};

/*
 * Other GNSS birds reuse GPS PRNs.
 * It is an NMEA0183 convention to map them to pseudo-PRNs 65..437.
 * Very dependent on NMEA version.
 * (some other GPS receivers push them to 33 and above).
 */
#define GLONASS_PRN_OFFSET      64

/*
 * The structure describing the pseudorange errors (GPGST)
 */
struct gst_t {
    timespec_t utctime;
    double rms_deviation;
    double smajor_deviation;
    double sminor_deviation;
    double smajor_orientation;
    double lat_err_deviation;
    double lon_err_deviation;
    double alt_err_deviation;
};

typedef uint64_t gps_mask_t;

// basic data, per PRN, from GPGSA and GPGSV, or GPS binary messages
// Note: u-blox 9 no longer uses PRN
struct satellite_t {
    /* SNR. signal-to-noise ratio, 0 to 254 dB, u-blox can be 0 to 63.
     * -1 for n/a */
    double ss;
    /* PRN of this satellite, 1 to 437, 0 for n/a
     * sadly there is no standard, but many different implementations of
     * how to code PRN
     */
    int16_t PRN;          // PRN numbering per NMEA 2.x to 4.0, not 4.10
    double elevation;     // elevation of satellite, -90 to 90 deg, NAN for n/a
    double azimuth;       // azimuth, 0 to 359 deg, NAN1 for n/a
    double prRes;               // Pseudorange residual, meters
    bool used;            // this satellite used in solution
    /* Quality Indicator
     * -1 = invalid, ignore
     * 0 = no signal
     * 1 = searching signal
     * 2 = signal acquired
     * 3 = signal detected but unusable
     * 4 = code locked and time synchronized
     * 5, 6, 7 = code and carrier locked and time synchronized
     */
    int8_t qualityInd;
    /* gnssid:svid:sigid, as defined by u-blox 8/9:
     *  gnssid        svid (native PRN)
     *  0 = GPS           1-32
     *  1 = SBAS          120-158
     *  2 = Galileo       1-36
     *  3 - BeiDou        1-37
     *  4 = IMES          1-10
     *  5 = QZSS          1-5       Undocumented u-blox goes to 7
     *  6 = GLONASS       1-32, 255
     *  7 = NavIC (IRNSS) 1-11       ZED-F9T
     *
     * gnssid:svid:sigid, as defined by NMEA 4.11, NOT USED HERE!
     *  1 = GPS       1-32
     *  1 = SBAS      33-64, 152-158
     *  1 = QZSS      193-202  (u-blox extended NMEA 4.10)
     *  2 = GLONASS   65-96, null
     *  3 = Galileo   1-36
     *  4 - BeiDou    1-37
     *  5 = QZSS      1-10 (NMEA 4.11)
     *  6 = NavIC (IRNSS)               NMEA 4.11+
     *  x = IMES      173-182 (u-blox extended NMEA 3.10)
     *
     * Note: other GNSS receivers use different mappings!
     */
    uint8_t gnssid;
// defines for u-blox gnssId, as used in satellite_t
#define GNSSID_GPS 0
#define GNSSID_SBAS 1
#define GNSSID_GAL 2
#define GNSSID_BD 3
#define GNSSID_IMES 4
#define GNSSID_QZSS 5
#define GNSSID_GLO 6
#define GNSSID_IRNSS 7            // ZED-F9T
#define GNSSID_CNT 8              // count for array size

    // ignore gnssid and sigid if svid is zero
    uint8_t svid;
    /* sigid as defined by u-blox 9/10, and used here
     * BeiDou:   0 = B1I D1, 1 = B1I D2, 2 = B2I D1, 3 = B2I D2, 7 = B2a
     * Galileo:  0 = E1 C, 1 = E1 B, 3 = E5 aI, 4 = E5 aQ, 5 = E5 bl, 6 = E5 bQ
     * GLONASS:  0 = L1 OF, 2 = L2 OF
     * GPS:      0 = L1C/A, 3 = L2 CL, 4 = L2 CM, 6 = L5 I, 7 = L5 Q
     * IRNSS:    ??
     * QZSS:     0 = L1C/A, 4 = L2 CM, 5 = L2 CL
     * SBAS:     0 = L1C/A, ? = L5I
     *
     * sigid as defined by NMEA 4.10, according to Skytrak, NOT used here
     * Galileo:
     *   0  All signals
     *   1  E5a  (aI and aQ)
     *   2  E5b  (bI and bQ)
     *   3  E5 a+b
     *   4  E6-A
     *   5  E6-BC
     *   6  L1-A
     *   7  L1-B and L1-C (E1-C and E1-B)
     * GLONASS:
     *   0  All signals-
     *   1  G1 C/A  (L1-OF)
     *   2  G1P
     *   3  G2 C/A  (L2 OF)
     *   4  GLONASS (M) G2P
     * GPS:
     *   0  All signals
     *   1  L1 C/A
     *   2  L1 P(Y)
     *   3  L1C
     *   4  L2 P(Y)
     *   5  L2C-M
     *   6  L2C-L
     *   7  L5-I
     *   8  L5-Q
     * IRNSS:
     *   4  L5
     * QZSS:     not defined
     *
     * Additional sigid as defined by NMEA 4.11, NOT used here
     * BeiDou:
     *   According to u-blox
     *     1 = B1 D1, 1 = B1 D2, 5 = B2 a, 11(8) = B2 D1, 11(8) = B2 D2
     *   According to Skytrak
     *     0  All signals
     *     1  B1  (b1-d1 AND b1-d2)
     *     2  B2A
     *     3  B2
     *     4  B3
     *     5  B1C
     * QZSS:     1 = L1C/A
     */
    uint8_t sigid;
    int8_t freqid;              // The GLONASS (Only) frequency, 0 - 13
    uint8_t health;             // 0 = unknown, 1 = healthy, 2 = unhealthy
#define SAT_HEALTH_UNK 0
#define SAT_HEALTH_OK 1
#define SAT_HEALTH_BAD 2

};

/* attitude_t was oringally for real IMUs that are syncronous
 * to the GNSS epoch.  Skytrak introduced a "moving base/rover"
 * that is used as a "GNSS Compass".  Essentially a synthetic
 * IMU.  To support this, related data (baseline_t) is also here.
 */
struct attitude_t {
    timespec_t  mtime;  // time of measurement
    // arbitrary time tag (see UBX-ESF-MEAS), 32 bit unsigned
    unsigned long timeTag;
    /* source message name.
     * Used to disambiguate UBX-ESF-RAW and UBX-ESF-MEAS
     * Also used to mark this struct as used
     */
    char msg[16];
    double acc_len;     // unitvector sqrt(x^2 + y^2 +z^2)
    // u-blox, acc_X ==  24 bit signed / 1024
    double acc_x;       // x-axis acceleration (m/s^2)
    double acc_y;       // y-axis acceleration (m/s^2)
    double acc_z;       // x-axis acceleration (m/s^2)
    double depth;
    double dip;
    // u-blox, gyro_temp ==  24 bit signed / 100
    double gyro_temp;   // deg C
    // u-blox, gyro_X ==  24 bit signed / 4096
    double gyro_x;      // deg/s^2
    double gyro_y;      // deg/s^2
    double gyro_z;      // deg/s^2
    double heading;     // true heading
    double mheading;    // magnetic heading
    double mag_len;     // unitvector sqrt(x^2 + y^2 +z^2)
    double mag_x;
    double mag_y;
    double mag_z;
    double pitch;       // deg
    double roll;        // deg
    double rot;         // rate of turn.  degrees / minute
    double temp;        // deg C
    double yaw;         // deg
    // compass status -- TrueNorth (and any similar) devices only
    char mag_st;
    char pitch_st;
    char roll_st;
    char yaw_st;
    struct baseline_t base;  // baseline from moving base
};

struct dop_t {
    // Dilution of precision factors
    double xdop, ydop, pdop, hdop, vdop, tdop, gdop;
};

struct oscillator_t {
    bool running;                       // oscillator is running
    bool reference;                     // PPS reference is avai/able
    bool disciplined;                   // oscillator is GPS-dis/ipli/ed
    int delta;                          // last observed PPS del/a
};

// data buffers for reading files or sockets
struct gps_data_t;   // forward declaration of gpss_data_t;

/*
 * Main structure that includes all previous substructures
 */

struct gps_data_t {
    gps_mask_t set;     // has field been set since this was last cleared?
    // Not required, but a good idea if these match the list in gps/gps.py.in
#define ONLINE_SET      (1llu<<1)
#define TIME_SET        (1llu<<2)
#define TIMERR_SET      (1llu<<3)
#define LATLON_SET      (1llu<<4)
#define ALTITUDE_SET    (1llu<<5)
#define SPEED_SET       (1llu<<6)
#define TRACK_SET       (1llu<<7)
#define CLIMB_SET       (1llu<<8)
#define STATUS_SET      (1llu<<9)
#define MODE_SET        (1llu<<10)
#define DOP_SET         (1llu<<11)
#define HERR_SET        (1llu<<12)
#define VERR_SET        (1llu<<13)
#define ATTITUDE_SET    (1llu<<14)
#define SATELLITE_SET   (1llu<<15)
#define SPEEDERR_SET    (1llu<<16)
#define TRACKERR_SET    (1llu<<17)
#define CLIMBERR_SET    (1llu<<18)
#define DEVICE_SET      (1llu<<19)
#define DEVICELIST_SET  (1llu<<20)
#define DEVICEID_SET    (1llu<<21)
#define RTCM2_SET       (1llu<<22)
#define RTCM3_SET       (1llu<<23)
#define AIS_SET         (1llu<<24)
#define PACKET_SET      (1llu<<25)
#define SUBFRAME_SET    (1llu<<26)
#define GST_SET         (1llu<<27)
#define VERSION_SET     (1llu<<28)
#define POLICY_SET      (1llu<<29)
#define LOGMESSAGE_SET  (1llu<<30)
#define ERROR_SET       (1llu<<31)
#define TOFF_SET        (1llu<<32)      // not yet used
#define PPS_SET         (1llu<<33)
#define NAVDATA_SET     (1llu<<34)
#define OSCILLATOR_SET  (1llu<<35)
#define ECEF_SET        (1llu<<36)
#define VECEF_SET       (1llu<<37)
#define MAGNETIC_TRACK_SET (1llu<<38)
#define RAW_SET         (1llu<<39)
#define NED_SET         (1llu<<40)
#define VNED_SET        (1llu<<41)
#define LOG_SET         (1llu<<42)
#define IMU_SET         (1llu<<43)
#define EOF_SET         (1llu<<44)
#define SET_HIGH_BIT    45
    timespec_t online;          /* NZ if GPS is on line, 0 if not.
                                 *
                                 * Note: gpsd clears this time when sentences
                                 * fail to show up within the GPS's normal
                                 * send cycle time. If the host-to-GPS
                                 * link is lossy enough to drop entire
                                 * sentences, this field will be
                                 * prone to false zero values.
                                 */

    struct gps_fix_t    fix;    // accumulated PVT data

    int leap_seconds;           // Unix secs to UTC (GPS-UTC offset)
    // precision of fix -- valid if satellites_used > 0
    int satellites_used;        // Number of satellites used in solution
    struct dop_t dop;

    // satellite status -- valid when satellites_visible > 0
    timespec_t skyview_time;    // skyview time
    int satellites_visible;     // # of satellites in view
    struct satellite_t skyview[MAXCHANNELS];


    struct {
        timespec_t time;
        int ndevices;
    } devices;

    // pack things never reported together to reduce structure size
#define UNION_SET       (AIS_SET|ERROR_SET|GST_SET| \
                         LOGMESSAGE_SET|OSCILLATOR_SET|PPS_SET|RAW_SET| \
                         RTCM2_SET|RTCM3_SET|SUBFRAME_SET|TOFF_SET|VERSION_SET)

    union {
        struct gst_t gst;
        struct oscillator_t osc;
        char error[256];
    };
    /* attitude and imu are similar
     * attitude is synchronous to the GNNS epoch, and cumulative in the epoch
     * imus is async to the epoch, and sent immediately
     *
     */
    struct attitude_t attitude;
    // u-blox 8 seems to need 10 IMU for UBX-ESF-RAW
    struct attitude_t imu[10];
    // quantization error adjustment to PPS. aka "sawtooth" correction
    long qErr;                  // offset in picoseconds (ps)
};

// dependencies on struct gps_data_t end here

extern void gps_clear_att(struct attitude_t *);
extern void gps_clear_dop( struct dop_t *);
extern void gps_clear_fix(struct gps_fix_t *);
extern void gps_merge_fix(struct gps_fix_t *, gps_mask_t, struct gps_fix_t *);
extern const char *gps_maskdump(gps_mask_t);

extern double safe_atof(const char *);
extern time_t mkgmtime(struct tm *);
extern char *timespec_to_iso8601(timespec_t t, char[], size_t len);
extern double earth_distance(double, double, double, double);
extern double earth_distance_and_bearings(double, double, double, double,
                                          double *,
                                          double *);
extern double wgs84_separation(double, double);
extern double mag_var(double, double);
extern void datum_code_string(int code, char *buffer, size_t len);
extern short ubx2_to_prn(int gnssId, int svId);

// some multipliers for interpreting GPS output

/* International Foot to Meters, exact
 * Note: not the same as the USA Survey Foot to meters:
 *   approximately: 0.304800609601.  exactly: (1200 / 3937)
 * Some states use the International Foot, not the USA Survey Foot */
#define FEET_TO_METERS  0.3048                   // intl feet to meters, exact
#define METERS_TO_FEET  (1 / FEET_TO_METERS)     // meters to intl feet, exact

#define MILES_TO_METERS 1.609344                  // Miles to meters, exact
#define METERS_TO_MILES (1 / MILES_TO_METERS)     // Meters to miles, exact
#define FATHOMS_TO_METERS 1.8288                  // Fathoms to meters, exact
#define METERS_TO_FATHOMS (1 / FATHOMS_TO_METER)  // Meters to fathoms, exact

// gpsd uses the international nautical mile, same as USA nautical mile
// different from UK nautical mile
#define KNOTS_TO_MPH    (1852 / 1609.344)   // Knots to miles per hour, exact
#define KNOTS_TO_KPH    1.852          // Knots to kilometers per hour, exact
// Knots to meters per second, exact, sort of.
// (double) needed to prevent non conforming CC from promoting to long double
#define KNOTS_TO_MPS (double)(KNOTS_TO_KPH / 3.6)
#define MPS_TO_KPH      3.6            // Meters per second to klicks/hr, exact
#define MPS_TO_MPH   (1 / 0.44704)    // Meters/second to miles per hour, exact
#define MPS_TO_KNOTS (3600.0 / 1852.0)     // Meters per second to knots, exact
// miles and knots are both the international standard versions of the units

// angle conversion multipliers
// IS-GPS-200, and Galileo_OS_SIS_ICD_v2.0.pdf, use pi = 3.1415926535898
#define GPS_PI          3.1415926535897932384626433832795029
#define RAD_2_DEG       57.2957795130823208767981548141051703
#define DEG_2_RAD       0.0174532925199432957692369076848861271

// other mathematical constants
#define GPS_LN2         0.693147180559945309417232121458176568


// WGS84(G1674) degining parameters
/* https://en.wikipedia.org/wiki/Geodetic_datum
 * Section #World_Geodetic_System_1984_(WGS_84)
 *
 * http://www.unoosa.org/pdf/icg/2012/template/WGS_84.pdf
 */
#define WGS84A 6378137.0                // equatorial radius (semi-major axis)
#define WGS84F 298.257223563            // flattening
#define WGS84B 6356752.314245           // polar radius (semi-minor axis)
/* 1st eccentricity squared = (WGS84A ^ 2 + WGS84B ^ 2) / (WGS84A ^ 2)
 * precomputed so C does not recompute every time */
#define WGS84E 0.006694379990197585     // 1st eccentricity squared
/* 2nd eccentricity squared = ((WGS84A ^ 2 - WGS84B ^ 2) / (WGS84B ^ 2)
 * precomputed so C does not recompute every time */
#define WGS84E2 0.006739496742333464    // 2nd eccentricy squared

#define CLIGHT      299792458.0  // speed of light (m/s)


#ifdef __cplusplus
}  // End of the 'extern "C"' block
#endif

#endif  // _GPSD_GPS_H_

// vim: set expandtab shiftwidth=4
